/*
 * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.io;

/**
 * 该类实现缓冲输出流。
 * 通过建立一个这样的输出流，应用程序可以将很多字节一次写入到依赖的输出流，而不必为每个写入的字节调用依赖的输出流的write方法。
 *
 * @author  Arthur van Hoff
 * @since   JDK1.0
 */
public
class BufferedOutputStream extends FilterOutputStream {
    /**
     * 存储数据的内部缓冲区。
     */
    protected byte buf[];

    /**
     * 缓冲区中的有效字节数。这个值总是在0到buf.length范围内;
     * 元素buf[0]到buf[count-1]包含有效的字节数据。
     */
    protected int count;

    /**
     * 创建一个新的缓冲输出流，以将数据写入指定的底层输出流。
     * 缓冲区大小为8192个byte
     *
     * @param   out   the underlying output stream.
     */
    public BufferedOutputStream(OutputStream out) {
        this(out, 8192);
    }

    /**
     * 创建一个新的缓冲输出流，以使用指定的缓冲大小，将数据写入指定的底层输出流。
     *
     * @param   out    the underlying output stream.
     * @param   size   the buffer size.
     * @exception IllegalArgumentException if size &lt;= 0.
     */
    public BufferedOutputStream(OutputStream out, int size) {
        super(out);
        if (size <= 0) {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        // 创建size个byte大小的缓冲区
        buf = new byte[size];
    }

    /** 刷新内部缓存*/
    private void flushBuffer() throws IOException {
        if (count > 0) {
        	// out写入buf中，从0开始，count个字节
            out.write(buf, 0, count);
            // 设置缓冲区指针为0
            count = 0;
        }
    }

    /**
     * 将指定的字节写入此缓冲输出流。
     *
     * @param      b   the byte to be written.
     * @exception  IOException  if an I/O error occurs.
     */
    public synchronized void write(int b) throws IOException {
    	// 如果缓冲区溢出，刷新缓冲区，将缓冲区的数据写入out中
        if (count >= buf.length) {
            flushBuffer();
        }
        // 设置buf[count]为b
        buf[count++] = (byte)b;
    }

    /**
     * 将指定字节数组从off位置开始的len字节写入此缓冲输出流。
     *
     * <p> 通常，该方法将给定数组中的字节存储到这个流的缓冲区中，根据需要将缓冲区刷新到底层输出流中。
     * 但是，如果需要的长度至少与流的缓冲区一样大，那么该方法将刷新缓冲区并直接将字节写入底层输出流。
     * 因此，冗余的BufferedOutputStreams将不会不必要地复制数据。
     *
     * @param      b     the data.
     * @param      off   the start offset in the data.
     * @param      len   the number of bytes to write.
     * @exception  IOException  if an I/O error occurs.
     */
    public synchronized void write(byte b[], int off, int len) throws IOException {
        if (len >= buf.length) {
            /* 如果请求长度超过了输出缓冲区的大小，则刷新输出缓冲区，然后直接写入数据。
               通过这种方式，缓冲流将无害地倾泻而下。
               */
            flushBuffer();
            out.write(b, off, len);
            return;
        }
        // 如果缓冲区溢出，刷新缓冲区，将缓冲区的数据写入out中
        if (len > buf.length - count) {
            flushBuffer();
        }
        // 复制b的字节到buf中
        System.arraycopy(b, off, buf, count, len);
        count += len;
    }

    /**
     * 刷新此缓冲的输出流。
     * 这强制将任何缓存的输出字节写入底层输出流。
     *
     * @exception  IOException  if an I/O error occurs.
     * @see        java.io.FilterOutputStream#out
     */
    public synchronized void flush() throws IOException {
        flushBuffer();
        out.flush();
    }
}
